package adapletplugin.editors.pages;

import objects.IObject;
import objects.Interface;
import objects.MappingFile;
import objects.ReferenceType;
import objects.RelToRel;
import objects.Relationship;
import objects.Table;
import objects.Type;

import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.IManagedForm;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.FormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;

import sections.ISection.Section;
import adapletplugin.dialogs.SingleQuestionDialog;
import adapletplugin.editors.InterfaceEditor;
import adapletplugin.editors.MapFileEditor;
import adapletplugin.editors.RefTypeEditor;
import adapletplugin.editors.RelEditor;
import adapletplugin.editors.RelToRelEditor;
import adapletplugin.editors.TableEditor;
import adapletplugin.editors.TypeEditor;
import adapletplugin.editors.input.MapFileEditorInput;
import adapletplugin.editors.input.MapTableInput;

public class MapFileEditorPage extends FormPage
{
	private ScrolledForm fForm;
	private MappingFile fMap;
	private FormToolkit fToolkit;

	private Combo sectionChooser;
	private Composite rightArea;
	private Composite hiddenArea;

	private Button newButton;
	private TableViewer tableViewer;
	private IObject focusObject;
	private MapTableInput tableInput;

	private TableEditor tableEditor;
	private TypeEditor typeEditor;
	private RefTypeEditor refTypeEditor;
	private RelEditor relEditor;
	private RelToRelEditor relToRelEditor;
	private InterfaceEditor interfaceEditor;

	public MapFileEditorPage(FormEditor editor, String id, String title)
	{
		super(editor, id, title);

		fMap = ((MapFileEditorInput) editor.getEditorInput()).getMapFile();
	}

	@Override
	protected void createFormContent(IManagedForm managedForm)
	{
		fForm = managedForm.getForm();
		fForm.setText(fMap.getMapFileName());

		fToolkit = managedForm.getToolkit();

		Composite body = fForm.getBody();

		body.setLayout(new GridLayout(1, true));

		Composite mainArea = fToolkit.createComposite(body, SWT.NULL);
		mainArea.setLayout(new GridLayout(2, true));
		mainArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		Composite leftArea = fToolkit.createComposite(mainArea, SWT.V_SCROLL);
		leftArea.setLayout(new GridLayout(1, true));
		leftArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		Composite header = fToolkit.createComposite(leftArea);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		header.setLayout(layout);
		header.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

		sectionChooser = new Combo(header, SWT.DROP_DOWN | SWT.READ_ONLY);
		sectionChooser.add("Tables");
		sectionChooser.add("Types");
		sectionChooser.add("Reference Types");
		sectionChooser.add("Relationships");
		sectionChooser.add("RelToRels");
		sectionChooser.add("Interfaces");
		sectionChooser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

		sectionChooser.addSelectionListener(createSectionChooserListener());

		newButton = fToolkit.createButton(header, "New", SWT.PUSH);
		newButton.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, false));
		newButton.addSelectionListener(createButtonListener());

		tableViewer = new TableViewer(leftArea, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL);
		tableViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		tableViewer.addDoubleClickListener(createDoubleClickListener());
		tableViewer.addSelectionChangedListener(createTableListener());
		tableViewer.setContentProvider(new MapTableContentProvider());
		tableViewer.setLabelProvider(new MapTableLabelProvider());

		tableInput = new MapTableInput(fMap, Section.TABLE);
		tableViewer.setInput(tableInput);

		rightArea = fToolkit.createComposite(mainArea, SWT.BORDER);
		rightArea.setLayout(new GridLayout(1, true));
		rightArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

		hiddenArea = fToolkit.createComposite(body);
		hiddenArea.setLayout(new GridLayout());
		GridData gData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
		gData.heightHint = 0;
		hiddenArea.setLayoutData(gData);

		ScrolledComposite composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		tableEditor = new TableEditor(composite, fToolkit, (MapFileEditor) getEditor());

		composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		typeEditor = new TypeEditor(composite, fToolkit, (MapFileEditor) getEditor());

		composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		refTypeEditor = new RefTypeEditor(composite, fToolkit, (MapFileEditor) getEditor());

		composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		relEditor = new RelEditor(composite, fToolkit, (MapFileEditor) getEditor());

		composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		relToRelEditor = new RelToRelEditor(composite, fToolkit, (MapFileEditor) getEditor());

		composite = new ScrolledComposite(hiddenArea, SWT.V_SCROLL);
		interfaceEditor = new InterfaceEditor(composite, fToolkit, (MapFileEditor) getEditor());

		sectionChooser.select(0);
	}

	private ISelectionChangedListener createTableListener()
	{
		return new ISelectionChangedListener() {

			@Override
			public void selectionChanged(SelectionChangedEvent event)
			{
				focusObject = (IObject) ((IStructuredSelection) tableViewer.getSelection()).getFirstElement();

				if (focusObject == null)
				{
					tableEditor.setParent(hiddenArea);
					typeEditor.setParent(hiddenArea);
					refTypeEditor.setParent(hiddenArea);
					relEditor.setParent(hiddenArea);
					relToRelEditor.setParent(hiddenArea);
					interfaceEditor.setParent(hiddenArea);
				}
				else
				{
					switch (tableInput.getSection())
					{
					case TABLE:
						tableEditor.setParent(rightArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(hiddenArea);

						updateTableEditor();
						break;
					case TYPE:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(rightArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(hiddenArea);

						updateTypeEditor();
						break;
					case REF_TYPE:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(rightArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(hiddenArea);

						updateRefTypeEditor();
						break;
					case REL:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(rightArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(hiddenArea);

						updateRelEditor();
						break;
					case REL_TO_REL:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(rightArea);
						interfaceEditor.setParent(hiddenArea);

						updateRelToRelEditor();
						break;
					case INTERFACE:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(rightArea);

						updateInterfaceEditor();
						break;
					default:
						tableEditor.setParent(hiddenArea);
						typeEditor.setParent(hiddenArea);
						refTypeEditor.setParent(hiddenArea);
						relEditor.setParent(hiddenArea);
						relToRelEditor.setParent(hiddenArea);
						interfaceEditor.setParent(hiddenArea);
					}
				}

				rightArea.layout();
			}
		};
	}

	private IDoubleClickListener createDoubleClickListener()
	{
		return new IDoubleClickListener() {

			@Override
			public void doubleClick(DoubleClickEvent event)
			{
				// TODO Auto-generated method stub

			}
		};
	}

	private SelectionListener createButtonListener()
	{
		return new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e)
			{
				String currentType = sectionChooser.getText();
				Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();

				if (currentType.equals("Tables"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create Table",
							"Enter a name for the new table.", "Table Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						Table newTable = fMap.getTableSection().createNewTable(dialog.getResultString());
						focusObject = newTable;
						tableViewer.refresh();
					}
				}
				else if (currentType.equals("Types"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create Type",
							"Enter a name for the new type.", "Type Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						Type newType = fMap.getTypeSection().createNewType(dialog.getResultString());
						focusObject = newType;
						tableViewer.refresh();
					}
				}
				else if (currentType.equals("Reference Types"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create Reference Type",
							"Enter a name for the new reference type.", "Type Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						ReferenceType newRefType = fMap.getReferenceTypeSection().createNewReferenceType(
								dialog.getResultString());
						focusObject = newRefType;
						tableViewer.refresh();
					}
				}
				else if (currentType.equals("Relationships"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create Relationship",
							"Enter a name for the new relationship.", "Relationship Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						Relationship newRel = fMap.getRelationshipSection().createNewRelationship(
								dialog.getResultString());
						focusObject = newRel;
						tableViewer.refresh();
					}
				}
				else if (currentType.equals("RelToRels"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create RelToRel",
							"Enter a name for the new RelToRel.", "RelToRel Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						RelToRel newRelToRel = fMap.getRelToRelSection().createNewRelToRel(dialog.getResultString());
						focusObject = newRelToRel;
						tableViewer.refresh();
					}
				}
				else if (currentType.equals("Interfaces"))
				{
					SingleQuestionDialog dialog = new SingleQuestionDialog(shell, "Create Interface",
							"Enter a name for the new interface.", "Interface Name");

					dialog.create();
					dialog.open();

					if (dialog.getReturnCode() == Window.OK)
					{
						Interface newInterface = fMap.getInterfaceSection()
								.createNewInterface(dialog.getResultString());
						focusObject = newInterface;
						tableViewer.refresh();
					}
				}
			}
		};
	}

	private SelectionListener createSectionChooserListener()
	{
		return new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e)
			{
				String currentType = sectionChooser.getText();

				if (currentType.equals("Tables"))
				{
					tableInput.updateSection(Section.TABLE);
				}
				else if (currentType.equals("Types"))
				{
					tableInput.updateSection(Section.TYPE);
				}
				else if (currentType.equals("Reference Types"))
				{
					tableInput.updateSection(Section.REF_TYPE);
				}
				else if (currentType.equals("Relationships"))
				{
					tableInput.updateSection(Section.REL);
				}
				else if (currentType.equals("RelToRels"))
				{
					tableInput.updateSection(Section.REL_TO_REL);
				}
				else if (currentType.equals("Interfaces"))
				{
					tableInput.updateSection(Section.INTERFACE);
				}

				focusObject = null;
				tableViewer.refresh();
			}
		};
	}

	private class MapTableLabelProvider extends LabelProvider implements ITableLabelProvider
	{

		@Override
		public Image getColumnImage(Object element, int columnIndex)
		{
			return null;
		}

		@Override
		public String getColumnText(Object element, int columnIndex)
		{
			return ((IObject) element).getObjectName();
		}

	}

	private class MapTableContentProvider implements IStructuredContentProvider
	{

		@Override
		public void dispose()
		{

		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
		{
			viewer.refresh();
		}

		@Override
		public Object[] getElements(Object inputElement)
		{
			MapTableInput mapTableInput = (MapTableInput) inputElement;

			return mapTableInput.getData();
		}

	}

	private void updateInterfaceEditor()
	{
		interfaceEditor.updateData(focusObject);
	}

	private void updateRelEditor()
	{
		relEditor.updateData(focusObject);
	}

	private void updateRefTypeEditor()
	{
		refTypeEditor.updateData(focusObject);
	}

	private void updateTypeEditor()
	{
		typeEditor.updateData(focusObject);
	}

	private void updateTableEditor()
	{
		tableEditor.updateData(focusObject);
	}

	private void updateRelToRelEditor()
	{
		relToRelEditor.updateData(focusObject);
	}
}
